package com.motu.vertx.module.utility.login;

import com.google.common.base.Charsets;
import com.google.common.primitives.Bytes;
import com.motu.vertx.module.utility.base.BaseServerParam;
import com.motu.vertx.module.utility.base.ServerConfig;
import com.motu.vertx.module.utility.base.BaseRedisKey;
import com.motu.vertx.module.utility.redis.RedisTools;
import com.motu.vertx.module.utility.toolset.ErrorWord;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.handler.sockjs.impl.StringEscapeUtils;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

public class LoginManager {

    public final static Logger logger = LoggerFactory.getLogger(LoginManager.class);

    public static final int HTTP_REQUEST_TIMEOUT = 5000;// http请求超时时间(毫秒)

    // 新的类型统一在Utility项目的LoginTypeEnum定义
    public static final int LOGIN_TYPE_GUEST = 0;//游客帐号
    public static final int LOGIN_TYPE_MOTU = 1;//魔兔帐号
    public static final int LOGIN_TYPE_WECHAT = 2;//微信帐号
    public static final int LOGIN_TYPE_QQ = 3;//QQ帐号
    public static final int LOGIN_TYPE_GAMECENTER = 4;//GameCenter帐号
    public static final int LOGIN_TYPE_GOOGLE = 5;//google帐号
    public static final int LOGIN_TYPE_CHANGMENG = 6;//畅梦帐号
    public static final int LOGIN_TYPE_9377 = 7;//9377帐号
    public static final int LOGIN_TYPE_MOTU_SDK = 8;//魔兔SDK
    public static final int LOGIN_TYPE_MOTU_37 = 9;//37互娱
    public static final int LOGIN_TYPE_APPLE = 10;//苹果账号
    public static final int LOGIN_TYPE_XINGHUI = 11;//星辉账号
    public static final int LOGIN_TYPE_FACEBOOK = 12;//facebook账号
    public static final int LOGIN_TYPE_MUYOU = 13;//沐游
    public static final int LOGIN_TYPE_UJOY = 14;//ujoy
    public static final int LOGIN_TYPE_HUAWEI = 15;//华为
    public static final int LOGIN_TYPE_QOOAPP = 16;//QooApp
    public static final int LOGIN_TYPE_VNG = 17;//vng
    public static final int LOGIN_TYPE_WECHAT_GAME = 18;//微信小游戏
    public static final int LOGIN_TYPE_TITOK_GAME = 26;//抖音小游戏


    public static Future<String> checkLoginToken(WebClient webClient, String account, String token, int platform) {
        Promise<String> future = Promise.promise();
        JsonObject params = new JsonObject();
        params.put("gameid", BaseServerParam.MOTU_SDK_GAMEID);
        params.put("acc", account);
        params.put("token", token);
        params.put("platform", platform);
        String requestUrl = BaseServerParam.MOTU_SDK_URL + "/checktoken";
//		MainVerticle.logger.info("###checkLoginToken requestUrl = " + requestUrl + " params = " + params);
        webClient.postAbs(requestUrl).timeout(HTTP_REQUEST_TIMEOUT).sendJsonObject(params, h -> {
            if (h.succeeded()) {
                HttpResponse<Buffer> response = h.result();
                JsonObject resObj = response.bodyAsJsonObject();
                int resultCode = resObj.getInteger("code");
                String accountid = resObj.getString("accid");// 账号ID
//				MainVerticle.logger.info("###checkLoginToken success result = " + resObj.toString());
                if (resultCode == 0) {
                    future.complete(accountid);//token验证成功
                } else {
                    logger.error("checkLoginToken error resultCode = " + resultCode + " params = " + params.toString() + " !!!");
                    future.fail(h.cause());// token验证失败
                }
            } else {
                logger.error(Tool.getException(h.cause()));
                future.fail(h.cause());// token验证失败
            }
        });
        return future.future();
    }

    public static Future<JsonObject> checkLoginFianl(WebClient webClient, int accountType, String account, String motuToken, String sdkToken, int platform) {
        Promise<JsonObject> fut = Promise.promise();
        if (!Tool.isEmpty(motuToken)) {
            checkMotuToken(webClient, accountType, account, motuToken, fut);
        } else if (!Tool.isEmpty(sdkToken)) {//魔兔帐号SDK
            checkLoginMotuSDK(webClient, account, sdkToken, platform, fut);
        }
        return fut.future();
    }

    public static Future<JsonObject> checkLogin(WebClient webClient, int accountType, String account, String pwd, String extParam, boolean isMotuToken, int platform) {
        return checkLogin(webClient, accountType, account, pwd, extParam, isMotuToken, platform, "");
    }

    public static Future<JsonObject> checkLogin(WebClient webClient, int accountType, String account, String pwd, String extParam, boolean isMotuToken, int platform, String packageName) {
        Promise<JsonObject> fut = Promise.promise();
        if (isMotuToken) {
            checkMotuToken(webClient, accountType, account, pwd, fut);
        } else if (accountType == LOGIN_TYPE_MOTU) {//魔兔帐号
            checkLoginMotu(webClient, account, pwd, platform, fut);
        } else if (accountType == LOGIN_TYPE_WECHAT) {//微信帐号
            checkLoginWechat(webClient, account, pwd, extParam, fut);
        } else if (accountType == LOGIN_TYPE_QQ) {//微信帐号
            checkLoginQQ(webClient, account, pwd, extParam, fut);
        } else if (accountType == LOGIN_TYPE_GAMECENTER) {//gamecenter帐号
            checkLoginGameCenter(webClient, account, pwd, extParam, fut);
        } else if (accountType == LOGIN_TYPE_GOOGLE) {//google帐号
            checkLoginGoogle(webClient, account, pwd, extParam, fut);
        } else if (accountType == LOGIN_TYPE_CHANGMENG) {//畅梦帐号
            checkLoginChangmeng(webClient, account, pwd, fut);
        } else if (accountType == LOGIN_TYPE_9377) {//9377帐号
            checkLogin9377(webClient, account, pwd, extParam, fut);
        } else if (accountType == LOGIN_TYPE_MOTU_SDK) {//魔兔帐号SDK
            checkLoginMotuSDK(webClient, account, pwd, platform, fut);
        } else if (accountType == LOGIN_TYPE_MOTU_37) {//37互娱
            checkLogin37(webClient, account, pwd, extParam, fut);
        } else if (accountType == LOGIN_TYPE_XINGHUI) {//星辉
            // 星辉已经预先验证过了，这里就不用再验证了
            fut.complete(new JsonObject().put("ret", 0));
//			checkLoginXingHui(webClient,account, pwd, extParam, packageName,fut);
        } else if (accountType == LOGIN_TYPE_UJOY) {//ujoy
            checkLoginUjoy(webClient, account, pwd, extParam, packageName, fut);
        } else if (accountType == LOGIN_TYPE_QOOAPP) {//qooapp
            checkLoginQooApp(webClient, account, pwd, extParam, packageName, fut);
        } else if (accountType == LOGIN_TYPE_VNG) {//vng
            checkLoginVng(webClient, account, pwd, extParam, packageName, fut);
        } else if (accountType == LOGIN_TYPE_WECHAT_GAME) {//微信小游戏
            // 微信小游戏已经预先验证过了，这里就不用再验证了
            fut.complete(new JsonObject().put("ret", 0));
//			checkLoginWechatGame(webClient,account, pwd,extParam, fut);
        }
        return fut.future();
    }

    /***
     * 魔兔帐号登录验证
     * @param account
     * @param pwd
     * @param handler
     */
    public static void checkLoginMotu(WebClient webClient, String account, String pwd, int platform, Handler<AsyncResult<JsonObject>> handler) {

        // 已经没有游戏内账号，都是用sdk账号
        JsonObject obj = new JsonObject();
        handler.handle(Future.succeededFuture(obj.put("ret", ErrorWord.ACCOUNT_NOT_EXIST.value)));

//		account = account.toLowerCase();//全部转成小写
//		pwd = pwd.toLowerCase();//全部转成小写
//		final String pwd2 = pwd;
//		String sql1 = "SELECT pwd, pwd_salt,isguest FROM allaccount WHERE account = ? limit 1;";
//		JsonArray params1 = new JsonArray().add(account);
//		JsonObject obj = new JsonObject();
//		MysqlTool.queryJsonArrayFromDb(UtilityManager.jdbcClientServer, sql1, params1, checkRes -> {
//			if (checkRes.succeeded()) {
//				JsonArray array = checkRes.result();
//				if (array != null && array.size() == 1) {
//					JsonObject resObj = array.getJsonObject(0);
//					String dbpwd = resObj.getString("pwd");
//					String dbpwd_salt = resObj.getString("pwd_salt");
//					int isGuest = resObj.getInteger("isguest");
//					if (dbpwd.equalsIgnoreCase(MainVerticle.instance.authProvider.computeHash(pwd2, dbpwd_salt))) {
//						obj.put("ret", 0);
//						obj.put("isguest", isGuest);
//						handler.handle(Future.succeededFuture(obj));
//					} else {//密码错误
//						handler.handle(Future.succeededFuture(obj.put("ret", ErrorWord.PASSWORD_WRONG.value)));
//					}
//				} else {//帐号不存在
//					handler.handle(Future.succeededFuture(obj.put("ret", ErrorWord.ACCOUNT_NOT_EXIST.value)));
//				}
//			} else {//数据库查询失败
//				handler.handle(Future.succeededFuture(obj.put("ret", ErrorWord.MYSQL_QUERY_FAILED.value)));
//			}
//		});
    }

    public static void checkLoginMotuSDK(WebClient webClient, String account, String pwd, int platform, Handler<AsyncResult<JsonObject>> handler) {
        String token = pwd;
        Future<String> futLogin = LoginManager.checkLoginToken(webClient, account, token, platform);
        futLogin.onComplete(resLogin -> {
            if (resLogin.succeeded()) {// 登陆验证成功
//				MainVerticle.logger.info("checkLoginMotuSDK success !!!!");
                handler.handle(Future.succeededFuture(new JsonObject().put("ret", 0)));
            } else {// 登陆验证失败
//				MainVerticle.logger.info("checkLoginMotuSDK fail !!!!");
                handler.handle(Future.succeededFuture(new JsonObject().put("ret", ErrorWord.TOKEN_WRONG.value)));
            }
        });
    }

    public static void checkMotuToken(WebClient webClient, int accountType, String account, String token, Handler<AsyncResult<JsonObject>> handler) {
        String redisKey = BaseRedisKey.getAccountToken(accountType, account);
        //			logger.info("handleGameInit redisKey :"+redisKey);
        RedisTools.getHashJsonObject(redisKey, res2 -> {
            JsonObject obj = new JsonObject();
            if (res2.result() != null) {
                if (!res2.result().isEmpty() && res2.result().getString("token").equalsIgnoreCase(token)) {//验证token
                    obj.put("ret", 0);
                    handler.handle(Future.succeededFuture(obj));
                } else {
                    handler.handle(Future.succeededFuture(obj.put("ret", ErrorWord.TOKEN_WRONG.value)));
                }
            } else {
                handler.handle(Future.succeededFuture(obj.put("ret", ErrorWord.REDIS_QUERY_FAILED.value)));
            }
        });

    }

    /***
     * 微信登录验证
     * @param account
     * @param pwd
     * @param handler
     */
    public static void checkLoginWechat(WebClient webClient, String account, String pwd, String extParam, Handler<AsyncResult<JsonObject>> handler) {
        JsonObject params = new JsonObject(extParam);
        String access_token = pwd;//params.getString("access_token");
        String openid = params.getString("openid");
        String url = "https://api.weixin.qq.com/sns/auth?access_token=" + access_token + "&openid=" + openid;
        //		WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject resObj = response.bodyAsJsonObject();
                logger.info("$$$ checkLoginWechat url:" + url + " resObj:" + resObj.toString());
                int errorcode = resObj.getInteger("errcode");
                JsonObject obj = new JsonObject();
                obj.put("ret", errorcode == 0 ? 0 : ErrorWord.TOKEN_WRONG.value);
                handler.handle(Future.succeededFuture(obj));
            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLoginWechat:" + res.cause().getMessage());
            }

        });
    }

    /***
     * QQ登录验证
     * @param account
     * @param pwd
     * @param handler
     */
    public static void checkLoginQQ(WebClient webClient, String account, String pwd, String extParam, Handler<AsyncResult<JsonObject>> handler) {
        JsonObject params = new JsonObject(extParam);
        String openid = params.getString("openid");
        String appid = params.getString("appid");
        String url = "https://graph.qq.com/user/get_user_info?access_token=" + pwd + "&oauth_consumer_key=" + appid + "&openid=" + openid;
        //		WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
        logger.error("$$$ checkLoginQQ: url:" + url);
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject resObj = response.bodyAsJsonObject();
                logger.info("$$$ checkLoginQQ resObj:" + resObj.toString());
                int errorcode = resObj.getInteger("ret");
                JsonObject obj = new JsonObject();
                obj.put("ret", errorcode == 0 ? 0 : ErrorWord.TOKEN_WRONG.value);
                handler.handle(Future.succeededFuture(obj));
            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLoginQQ:" + res.cause().getMessage());

            }

        });
    }

    /***
     * facebook登录验证
     * @param short_token
     * @param handler
     */
    public static void checkLoginFacebook(WebClient webClient, String short_token, Handler<AsyncResult<JsonObject>> handler) {
        String appId = ServerConfig.getAppConfig().getString("facebook-appid");
        String appSecret = ServerConfig.getAppConfig().getString("facebook-appsecret");
        String url = "https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id=" + appId + "&client_secret=" + appSecret + "&fb_exchange_token=" + short_token;
        ;
        //		WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
        logger.error("$$$ checkLoginFacebook: url:" + url);
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject resObj = response.bodyAsJsonObject();
                logger.info("$$$ checkLoginFacebook resObj:" + resObj.toString());
                String access_token = resObj.getString("access_token");
                String url2 = "https://graph.facebook.com/me?access_token=" + access_token;
                //				WebClient webClient2 = WebClient.create(MainVerticle.instance.vertxInstance);
                webClient.getAbs(url2).timeout(30000l).send(res2 -> {
                    if (res2.succeeded()) {
                        HttpResponse<Buffer> response2 = res2.result();
                        JsonObject resObj2 = response2.bodyAsJsonObject();
                        resObj2.put("ret", 0);
                        handler.handle(Future.succeededFuture(resObj2));
                    } else {
                        JsonObject obj = new JsonObject();
                        obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                        handler.handle(Future.succeededFuture(obj));
                        logger.error("$$$ checkLoginFacebook:" + res2.cause().getMessage());

                    }
                });

            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLoginFacebook:" + res.cause().getMessage());

            }

        });
    }

    public static byte[] concatContent(String playerId, String bundleId, long timestamp, String salt)
            throws IOException {
        return Bytes.concat(playerId.getBytes(Charsets.UTF_8), bundleId.getBytes(Charsets.UTF_8), toBigEndian(timestamp),
                Base64.decodeBase64(salt));
    }

    private static byte[] toBigEndian(long value) {
        byte[] buffer = new byte[8];
        for (int i = 0; i < 8; i++) {
            buffer[7 - i] = (byte) (value & 0xff);
            value = value >> 8;
        }
        return buffer;
    }

    /**
     * @param publicKeyInputstream 访问publicKeyURL获得的字节流
     * @param sign                 客户端穿过来的sign，需要先进行base64decode
     * @param content              concatContent方法获得的字节数组
     * @return
     */
    private static boolean verifyGameCenterSign(InputStream publicKeyInputstream, byte[] sign, byte[] content) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("x.509");
            X509Certificate cer = (X509Certificate) cf.generateCertificate(publicKeyInputstream);
            cer.checkValidity();
            PublicKey publicKey = cer.getPublicKey();
            Signature signature = Signature.getInstance(cer.getSigAlgName());
            signature.initVerify(publicKey);
            signature.update(content);
            return signature.verify(sign);
        } catch (Exception e) {
            logger.error("$$$ verifyGameCenterSign:" + Tool.getException(e));
        }
        return false;
    }

    /**
     * 验证gamecenter登录，playerId赋值在account上传，其他参数用json格式放在extParam参数字段
     *
     * @param account
     * @param pwd
     * @param extParam
     * @param handler
     */
    public static void checkLoginGameCenter(WebClient webClient, String account, String pwd, String extParam, Handler<AsyncResult<JsonObject>> handler) {
        logger.info("checkLoginGameCenter account:" + account + "extParam:" + extParam);
        JsonObject params = new JsonObject(extParam);
        try {
            String playerId = account;
            String publicKeyUrl = params.getString("publicKeyUrl");
            String bundleId = params.getString("bundleID");
            long timestamp = params.getLong("timestamp");
            String salt = params.getString("salt");
            String sign = params.getString("signature");
            logger.info("checkLoginGameCenter publicKeyUrl:" + publicKeyUrl);
            logger.info("checkLoginGameCenter bundleId:" + bundleId);
            logger.info("checkLoginGameCenter timestamp:" + timestamp);
            logger.info("checkLoginGameCenter salt:" + salt);
            logger.info("checkLoginGameCenter sign:" + sign);
            byte[] data = concatContent(playerId, bundleId, timestamp, salt);
            byte[] signBytes = Base64.decodeBase64(sign);
            //			WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
            webClient.getAbs(publicKeyUrl).timeout(10000l).send(res -> {//使用异步访问gamecenter服务器
                if (res.succeeded()) {
                    HttpResponse<Buffer> response = res.result();
                    InputStream publicKeyInputStream = new ByteArrayInputStream(response.body().getBytes());
                    boolean result = verifyGameCenterSign(publicKeyInputStream, signBytes, data);
                    logger.info("checkLoginGameCenter account:" + account + "result:" + result);
                    JsonObject obj = new JsonObject();
                    obj.put("ret", result ? 0 : ErrorWord.TOKEN_WRONG.value);
                    handler.handle(Future.succeededFuture(obj));
                } else {
                    JsonObject obj = new JsonObject();
                    obj.put("ret", ErrorWord.NET_ERROR_TIMEOUT.value);
                    handler.handle(Future.succeededFuture(obj));
                    logger.error("$$$ checkLoginGameCenter:" + res.cause().getMessage());
                }
            });

            //			URL url = new URL(publicKeyUrl);
            //			HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
            //			httpCon.setConnectTimeout(50000);
            //			httpCon.setReadTimeout(50000);
            //			InputStream publicKeyInputStream  = httpCon.getInputStream();
            //
            //			//	    InputStream publicKeyInputStream = HttpHelper.get(publicKeyUrl);
            //			boolean result = verifyGameCenterSign(publicKeyInputStream , signBytes, data);
            //			logger.info("checkLoginGameCenter account:"+account+"result:"+result);
            //			JsonObject obj = new JsonObject();
            //			obj.put("ret", result?0:ErrorWord.TOKEN_WRONG.value);
            //			handler.handle(Future.succeededFuture(obj));
        } catch (Exception e) {
            JsonObject obj = new JsonObject();
            obj.put("ret", ErrorWord.INVALID_OPERATION.value);
            handler.handle(Future.succeededFuture(obj));
            logger.error("$$$ checkLoginGameCenter:" + Tool.getException(e));
        }

    }

    /***
     * 校验google登录
     * @param account google userid
     * @param pwd idTokenString
     * @param handler
     */
    public static void checkLoginGoogle(WebClient webClient, String account, String pwd, String extParam, Handler<AsyncResult<JsonObject>> handler) {
        //		import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
        //		import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
        //		import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
        //
        //		...
        logger.info("checkLoginGoogle account:" + account + " extParam:" + extParam);
        JsonObject params = new JsonObject(extParam);
        String client_id = params.getString("client_id");//MainVerticle.instance.config().getString("google-client-id");
        String id_token = params.getString("idtoken");
        logger.info("checkLoginGoogle client_id:" + client_id);
        logger.info("checkLoginGoogle id_token:" + id_token);
        String url = "https://oauth2.googleapis.com/tokeninfo?id_token=" + id_token;
        //		WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject resObj = response.bodyAsJsonObject();
                logger.info("$$$ checkLoginGoogle resObj:" + resObj.toString());
                if (resObj.containsKey("aud")) {
                    String aud = resObj.getString("aud");
                    if (aud.equalsIgnoreCase(client_id)) {
                        String sub = resObj.getString("sub");
                        if (sub.equalsIgnoreCase(account)) {
                            int exp = Integer.parseInt(resObj.getString("exp"));//过期时间
                            if (exp < TimeUtils.getCurTime()) {//token过期
                                handler.handle(Future.succeededFuture(new JsonObject().put("ret", ErrorWord.TOKEN_EXPIRED.value)));
                            } else {
                                handler.handle(Future.succeededFuture(new JsonObject().put("ret", 0)));
                            }
                        } else {
                            handler.handle(Future.succeededFuture(new JsonObject().put("ret", ErrorWord.ACCOUNT_NOT_EXIST.value)));
                        }
                    } else {
                        handler.handle(Future.succeededFuture(new JsonObject().put("ret", ErrorWord.BAD_PARAM.value)));
                    }
                } else {//无效token
                    handler.handle(Future.succeededFuture(new JsonObject().put("ret", ErrorWord.TOKEN_WRONG.value)));
                }
            } else {
                logger.error("$$$ checkLoginGoogle:" + res.cause().getMessage());
                handler.handle(Future.succeededFuture(new JsonObject().put("ret", ErrorWord.INVALID_OPERATION.value)));
            }

        });
        //		try {
        //			HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        //			GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(httpTransport, JacksonFactory.getDefaultInstance())
        //					// Specify the CLIENT_ID of the app that accesses the backend:
        //					.setAudience(Collections.singletonList(client_id))
        //					.setIssuer("accounts.google.com")
        //					// Or, if multiple clients access the backend:
        //					//.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
        //					.build();
        //			if(verifier == null) {
        //				JsonObject obj = new JsonObject();
        //				obj.put("ret", ErrorWord.NET_ERROR_TIMEOUT.value);
        //				handler.handle(Future.succeededFuture(obj));
        //				logger.error("checkLoginGoogle verifier == null");
        //			}else {
        //				// (Receive idTokenString by HTTPS POST)
        //
        //				GoogleIdToken idToken = null ;
        //				try {
        //					idToken = verifier.verify(id_token);
        //				} catch (GeneralSecurityException e) {
        //					logger.error("验证时出现GeneralSecurityException异常 "+Tool.getException(e));
        //				} catch (IOException e) {
        //					logger.error("验证时出现IOException异常 "+Tool.getException(e));
        //				}catch (Exception e) {
        //					logger.error("验证时出现Exception异常 "+Tool.getException(e));
        //				}
        //
        //				if(idToken != null) {
        //					Payload payload = idToken.getPayload();
        //					String userId = payload.getSubject();
        //					logger.info("checkLoginGoogle account:"+account+" pwd:"+pwd+" google userid:"+userId);
        //					JsonObject obj = new JsonObject();
        //					obj.put("ret", userId.equalsIgnoreCase(account)?0:ErrorWord.TOKEN_WRONG.value);
        //					handler.handle(Future.succeededFuture(obj));
        //				}else {
        //					logger.error("checkLoginGoogle idToken == null");
        //					JsonObject obj = new JsonObject();
        //					obj.put("ret", ErrorWord.INVALID_OPERATION.value);
        //					handler.handle(Future.succeededFuture(obj));
        //				}
        //			}
        //		} catch (GeneralSecurityException e1) {
        //			logger.error("checkLoginGoogle error1 "+e1.getMessage());
        //		} catch (IOException e1) {
        //			logger.error("checkLoginGoogle error2 "+e1.getMessage());
        //		}


    }

//	public static void createTestUser(){
//		for (int i = 0; i < 100; i++) {
//			incrTableId("userinfo").setHandler(getUserIdRes->{
//				if (getUserIdRes.succeeded()){
//					long userId = getUserIdRes.result();
//					if(userId < ServerParam.TABLE_INIT_ID) {
//						logger.error("### userId < ServerParam.TABLE_INIT_ID");
//						return;
//					}
//					int locId = 0;
//					int serverId = 1001;
//					String roleName = "test" + userId;
//					String sqlInsert = "insert into userinfo(id,serverid,username,icon,gender,location) values(?,?,?,?,?,?);";
//					JsonArray paramsInsert = new JsonArray();
//					paramsInsert.add(userId);
//					paramsInsert.add(serverId);
//					paramsInsert.add(roleName);
//					paramsInsert.add(0);
//					paramsInsert.add(0);
//					paramsInsert.add(locId);
//
//					MysqlTool.updateToDb(MainVerticle.instance.jdbcClientGame, sqlInsert, paramsInsert, resInsert->{
//						if(resInsert.succeeded()){
//							long uid = userId;
//							PBRoleInfo.Builder sb = PBRoleInfo.newBuilder();
//							sb.setUserId(uid);
//							sb.setServerId(serverId);
//							long channel = 0;
//							int accountType = 1;
//							int platform = 1;
//							String mac = "";
//							String udid = "";
//							String ip2 = "192.168.0.105";
//							int language = 1;
//							String account2 = "test";
//							String sqlInsert2 = "insert into userextinfo(id,sid,accountid,accounttype,platform,channel,mac,ip,udid,regtime,language) "
//									+ "values(?,?,?,?,?,?,?,?,?,?,?);";
//							JsonArray paramsInsert2 = new JsonArray();
//							paramsInsert2.add(uid);
//							paramsInsert2.add(serverId);
//							paramsInsert2.add(account2);
//							paramsInsert2.add(accountType);
//							paramsInsert2.add(platform);
//							paramsInsert2.add(channel);
//							paramsInsert2.add(mac);
//							paramsInsert2.add(ip2);
//							paramsInsert2.add(udid);
//							paramsInsert2.add(Tool.getCurTime());
//							paramsInsert2.add(language);
//							MysqlTool.updateToDb(MainVerticle.instance.jdbcClientGame, sqlInsert2, paramsInsert2, resInsert2->{
//								if(resInsert2.succeeded()){
//									// 把userinfo和userextinfo添加到redis中
//									String strUserinfoKey = "userinfo." + uid;
//									JsonObject objUserinfo = new JsonObject();
//									objUserinfo.put("id", uid);
//									objUserinfo.put("serverid", serverId);
//									objUserinfo.put("username", roleName);
//									objUserinfo.put("location", locId);
//									RedisTools.setHashJsonObject(MainVerticle.instance.redisClient, strUserinfoKey, objUserinfo, h->{
//										if (h.succeeded()){
//											String strUserextinfoKey = "userextinfo." + uid;
//											JsonObject objUserextinfo = new JsonObject();
//											objUserextinfo.put("id", uid);
//											objUserextinfo.put("sid", serverId);
//											objUserextinfo.put("accountid", account2);
//											objUserextinfo.put("platform", platform);
//											objUserextinfo.put("channel", channel);
//											objUserextinfo.put("mac", mac);
//											objUserextinfo.put("ip", ip2);
//											objUserextinfo.put("udid", udid);
//											objUserextinfo.put("regtime", Tool.getCurTime());
//											objUserextinfo.put("language", language);
//											objUserextinfo.put("accounttype", accountType);
//											RedisTools.setHashJsonObject(MainVerticle.instance.redisClient, strUserextinfoKey, objUserextinfo, h1->{
//												if (h1.succeeded()){
//													// 成功返回客户端
//													logger.info("### userid = " + userId + " add success !!!");
//												} else{
//													logger.error("### userid = " + userId + " add error 1");
//												}
//											});
//										} else{
//											logger.error("### userid = " + userId + " add error 2");
//										}
//									});
//								}else{
//									logger.error("### userid = " + userId + " add error 3");
//								}
//							});
//						}else{
//							logger.error("### userid = " + userId + " add error 4");
//						}
//					});
//				} else{
//					logger.error("### add user error 5");
//				}
//			});
//		}
//	}

    private static Future<Long> incrTableId(String key) {
        Promise<Long> promise = Promise.promise();
        //		logger.info("incrTableId key:"+key);
        long initId = BaseServerParam.TABLE_INIT_ID;
        RedisTools.hsetnx(RedisTools.getTableidKey(), key, String.valueOf(initId), h -> {
            if (h.succeeded()) {
                if (h.result()) {
                    logger.info("### table = " + key + " init id = " + initId);
                    promise.complete(initId);
                } else {
                    RedisTools.incrTableId(key, h2 -> {
                        if (h2.succeeded()) {
                            promise.complete(h2.result());
                        } else {
                            promise.fail(h2.cause());
                        }
                    });
                }
            } else {
                promise.fail(h.cause());
            }
        });
        return promise.future();
    }

    public static void checkLoginChangmeng(WebClient webClient, String account, String pwd, Handler<AsyncResult<JsonObject>> handler) {
        String url = "https://sdkv3.changmeng.com/passport/user/token-auth?uid=" + account + "&token=" + pwd;
        //		WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                String result = response.bodyAsString();
                logger.info("$$$ checkLoginChangemeng url:" + url + " result:" + result);
                JsonObject obj = new JsonObject();
                obj.put("ret", result.equalsIgnoreCase("success") ? 0 : ErrorWord.TOKEN_WRONG.value);
                handler.handle(Future.succeededFuture(obj));
            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLoginChangemeng:" + res.cause().getMessage());
            }

        });
    }

    public static void checkLogin9377(WebClient webClient, String account, String pwd, String extParam, Handler<AsyncResult<JsonObject>> handler) {
        long time = TimeUtils.getCurTime();
        int gameId = new JsonObject(extParam).getInteger("gameid");
        String sign = Tool.md5encrypt32(pwd + time + BaseServerParam.GAME_SECRET_KEY_9377);
        String url = "https://api.93wgames.com/user/cpToken?access_token=" + pwd + "&game_id=" + gameId + "&timestamp=" + time + "&sign=" + sign;
        //		WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject result = response.bodyAsJsonObject();
                int code = result.getInteger("code");
                logger.info("$$$ checkLogin9377 url:" + url + " result:" + result);
                JsonObject obj = new JsonObject();
                obj.put("ret", code == 1 ? 0 : ErrorWord.TOKEN_WRONG.value);
                handler.handle(Future.succeededFuture(obj));
            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLogin9377:" + res.cause().getMessage());
            }

        });
    }

    public static void checkLogin37(WebClient webClient, String account, String pwd, String extParam, Handler<AsyncResult<JsonObject>> handler) {
        long time = TimeUtils.getCurTime();
        JsonObject extParamObj = new JsonObject(extParam);
        int game_id = extParamObj.getInteger("game_id");
        String pid = extParamObj.getString("pid");
        String c_game_id = extParamObj.getString("c_game_id");
        String clientid = extParamObj.getString("clientid");

        String pst = pwd;
        Map<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("clientid", clientid);
        paramMap.put("pid", pid);
        paramMap.put("game_id", "" + game_id);
        paramMap.put("pst", pst);
        paramMap.put("time", "" + time);
        paramMap.put("c_game_id", "" + c_game_id);
//		paramMap.put("sign",ServerParam.GAME_SECRET_LOGIN_KEY_37);

        String url = "https://apimyh5.37.com/index.php?c=sdk-unified&a=validate";
        //		WebClient webClient = WebClient.create(MainVerticle.instance.vertxInstance);
        String postData = Tool.getSignCheckContent(paramMap, false);
        String sign = Tool.md5encrypt32(postData + "&" + BaseServerParam.GAME_SECRET_LOGIN_KEY_37);
        postData += "&sign=" + sign;
        Buffer buffer = Buffer.buffer(postData, "UTF-8");
        logger.info("checkLogin37 postData:" + postData + " len:" + buffer.length());
        webClient.postAbs(url).putHeader("content-type", "application/x-www-form-urlencoded").timeout(30000l).sendBuffer(buffer, res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject result = response.bodyAsJsonObject();

                int code = result.getInteger("code");
                logger.info("$$$ checkLogin37 url:" + url + " result:" + result);
                JsonObject obj = new JsonObject();
                if (code == 1) {
                    String uid = "" + result.getJsonObject("data").getLong("uid");
                    obj.put("ret", uid.equalsIgnoreCase(account) ? 0 : ErrorWord.ACCOUNT_NOT_EXIST.value);//判断sdk返回的accountid
                    handler.handle(Future.succeededFuture(obj));
                } else {
                    obj.put("ret", ErrorWord.TOKEN_WRONG.value);
                    handler.handle(Future.succeededFuture(obj));
                }


            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLogin9377:" + res.cause().getMessage());
            }

        });
    }

    public static void checkLoginXingHui(WebClient webClient, String account, String pwd, String extParam, String packageName, Handler<AsyncResult<JsonObject>> handler) {
        long time = TimeUtils.getCurTime();
        JsonObject extParamObj = new JsonObject(extParam);
        String app_id = extParamObj.getString("app_id");//游戏唯一ID
        String cch_id = extParamObj.getString("cch_id");//渠道商ID
        String access_token = pwd;
        Map<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("app_id", app_id);
        paramMap.put("cch_id", cch_id);
        paramMap.put("access_token", access_token);
        paramMap.put("tm", "" + time);

        // 根据包名获取密钥
        String key = new JsonObject(BaseServerParam.GAME_SECRET_LOGIN_KEY_XINGHUI).getString(packageName);

        String url = "https://sy-inner.rastargames.com/v1/verify/index";
        String postData = Tool.getSignCheckContent(paramMap, false);
        String sign = Tool.md5encrypt32(postData + "&" + key);
        postData += "&sign=" + sign;
        Buffer buffer = Buffer.buffer(postData, "UTF-8");
        logger.info("checkLoginXingHui postData:" + postData + " len:" + buffer.length());
        webClient.postAbs(url).putHeader("content-type", "application/x-www-form-urlencoded").timeout(30000l).sendBuffer(buffer, res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject result = response.bodyAsJsonObject();

                int code = result.getInteger("code");
                logger.info("$$$ checkLoginXingHui url:" + url + " result:" + result.toString());
                JsonObject obj = new JsonObject();
                if (code == 200) {
                    obj.put("ret", 0);
                    obj.put("accountid", result.getJsonObject("data").getString("openid"));// 星辉的账号id是验证token后获取
                    handler.handle(Future.succeededFuture(obj));
                } else {
                    obj.put("ret", ErrorWord.TOKEN_WRONG.value);
                    handler.handle(Future.succeededFuture(obj));
                }
            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLoginXingHui:" + res.cause().getMessage());
            }
        });
    }

    public static void checkLoginUjoy(WebClient webClient, String account, String pwd, String extParam, String packageName, Handler<AsyncResult<JsonObject>> handler) {
        JsonObject extParamObj = new JsonObject(extParam);
        int time = extParamObj.getInteger("time");// 登录时间

        // 根据包名获取密钥
        String key = new JsonObject(BaseServerParam.GAME_SECRET_LOGIN_KEY_UJOY).getString(packageName);
        String serverSign = Tool.md5encrypt32(account + "," + key + "," + time);
        JsonObject obj = new JsonObject();
        if (serverSign.equalsIgnoreCase(pwd)) {
            obj.put("ret", 0);
            handler.handle(Future.succeededFuture(obj));
        } else {
            logger.error("checkLoginUjoy sign error server = " + serverSign + " client = " + pwd);
            obj.put("ret", ErrorWord.TOKEN_WRONG.value);
            handler.handle(Future.succeededFuture(obj));
        }
    }

    /***
     * QooApp登录验证
     */
    public static void checkLoginQooApp(WebClient webClient, String account, String pwd, String extParam, String packageName, Handler<AsyncResult<JsonObject>> handler) {
        try {
            if (Tool.isEmpty(BaseServerParam.GAME_SECRET_LOGIN_KEY_QOOAPP)) {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.NOT_DATA.value);
                handler.handle(Future.succeededFuture(obj));
                return;
            }

            // 获取登录数据
            JsonObject objExtParam = new JsonObject(extParam);
            String algorithm = objExtParam.getString("algorithm");// 加密方法（sha1/sha256）
            String data = objExtParam.getString("data");
            data = StringEscapeUtils.unescapeJavaScript(data);
            data = data.replace("/", "\\/");

            // 获取公钥
            String pubKey = new JsonObject(BaseServerParam.GAME_SECRET_LOGIN_KEY_QOOAPP).getString(packageName);

            // 客户端签名
            String signature = pwd;

            logger.info("checkLoginQooApp account = {} algorithm = {} data = {} pubkey = {} sig = {}", account, algorithm, data, pubKey, signature);

            // 验证签名
            boolean result;
            if ("sha1".equalsIgnoreCase(algorithm)) {
                result = Tool.checkSHA1(data, signature, pubKey);
            } else if ("sha256".equalsIgnoreCase(algorithm)) {
                result = Tool.checkSHA256(data, signature, pubKey);
            } else {
                logger.error("checkLoginQooApp algorithm error = {} account = {}", algorithm, account);
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.BAD_PARAM.value);
                handler.handle(Future.succeededFuture(obj));
                return;
            }

            int ret = result ? ErrorWord.SUCCESS.value : ErrorWord.TOKEN_WRONG.value;
            JsonObject obj = new JsonObject();
            obj.put("ret", ret);
            handler.handle(Future.succeededFuture(obj));

        } catch (Exception e) {
            JsonObject obj = new JsonObject();
            obj.put("ret", ErrorWord.LOGIC_EXCEPTION.value);
            handler.handle(Future.succeededFuture(obj));
            logger.error("!!! checkLoginQooApp Exception:" + Tool.getException(e));
        }
    }

    public static void checkLoginVng(WebClient webClient, String account, String pwd, String extParam, String packageName, Handler<AsyncResult<JsonObject>> handler) {
        long time = TimeUtils.getCurTime();
        JsonObject extParamObj = new JsonObject(extParam);
        String userID = account;
        String sessionID = pwd;//vng sessionID
        String gameID = extParamObj.getString("gameID");//vng gameID

        // 根据包名获取密钥
        String key = new JsonObject(BaseServerParam.GAME_SECRET_LOGIN_KEY_VNG).getString(packageName);

        String url = "https://pp.m.zing.vn/api/login/checkSession";
        String checkInfo = key + gameID + userID + sessionID + time;
        String sign = Tool.md5encrypt32(checkInfo);
        String postData = "userID=" + userID + "&sessionID=" + sessionID + "&timestamp=" + time + "&gameID=" + gameID + "&sig=" + sign;
        Buffer buffer = Buffer.buffer(postData, "UTF-8");
        webClient.postAbs(url).putHeader("content-type", "application/x-www-form-urlencoded").timeout(30000l).sendBuffer(buffer, res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject result = response.bodyAsJsonObject();

                int code = result.getInteger("returnCode");
                JsonObject obj = new JsonObject();
                if (code == 1) {
                    obj.put("ret", 0);
                    logger.info("checkLoginVng success postData:" + postData);
                } else {
                    obj.put("ret", ErrorWord.TOKEN_WRONG.value);
                    logger.error("checkLoginVng error postData:" + postData + " result:" + result.toString());
                }
                handler.handle(Future.succeededFuture(obj));
            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("checkLoginVng error postData:" + postData + " cause:" + Tool.getException(res.cause()));
            }
        });
    }

    /***
     * 微信小游戏登录验证
     * @param account
     * @param pwd
     * @param handler
     */
    public static void checkLoginWechatGame(WebClient webClient, String account, String pwd, String extParam, Handler<AsyncResult<JsonObject>> handler) {
        JsonObject params = new JsonObject(extParam);
        String appid = params.getString("appid");
        String code = params.getString("code");
        String secret = BaseServerParam.WECHAT_GAME_LOGIN_KEY;
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code
                + "&grant_type=authorization_code";
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject resObj = response.bodyAsJsonObject();
                logger.info("$$$ checkLoginWechatGame url:" + url + " resObj:" + resObj.toString());
                int errorcode = resObj.containsKey("errcode") ? resObj.getInteger("errcode") : 0;
                JsonObject obj = new JsonObject();
                obj.put("ret", errorcode == 0 ? 0 : ErrorWord.TOKEN_WRONG.value);
                if (errorcode == 0) {
                    String accountid = resObj.containsKey("unionid") ? resObj.getString("unionid") : "";
                    if (Tool.isEmpty(accountid)){
                        obj.put("ret", ErrorWord.TOKEN_WRONG.value);
                    } else{
                        obj.put("accountid", accountid);
                        // 保存微信openid session_key
                        if (resObj.containsKey("openid")){
                            String openId = resObj.getString("openid");
                            String session_key = resObj.getString("session_key");
                            String key = BaseRedisKey.getWxOpenId(accountid);
                            RedisTools.setAndExpire(key, openId, Tool.WEEK);
                            RedisTools.setAndExpire(BaseRedisKey.getWxUserSessionkey(openId), session_key, Tool.DAY * 5);
                            obj.put("openId", openId);
                        }
                    }
                }
                handler.handle(Future.succeededFuture(obj));
            } else {
                JsonObject obj = new JsonObject();
                obj.put("ret", ErrorWord.INVALID_OPERATION.value);
                handler.handle(Future.succeededFuture(obj));
                logger.error("$$$ checkLoginWechatGame url:" + url + " cause:" + Tool.getException(res.cause()));
            }

        });
    }

//	/**
//	 * 推送头像审核消息
//	 * @param userId 用户ID
//	 * @param url 头像url
//	 */
//	public static void pushCheckHead(long userId, String url) {
//		CSGameSystemCheckHeadResponse.Builder response  = CSGameSystemCheckHeadResponse.newBuilder();
//		if (!Tool.isEmpty(url)){
//			response.setUrl(url);
//		}
//		JsonObject obj = new JsonObject().put("code", EnumCmdID.CMD_GAME_SYSTEM_CHECK_HEAD_VALUE).put("data",response.build().toByteArray());
//		pushToUsers(userId, obj);
//	}

//	/**
//	 * 给玩家推送消息
//	 * @param userId 用户id
//	 * @param obj 推送消息
//	 */
//	public static void pushToUsers(long userId,JsonObject obj){
//		String redisKey = RedisKey.getUserGateKey(userId);
//		RedisTools.get(MainVerticle.instance.redisClient, redisKey, handleGetGateKey->{
//			if (handleGetGateKey.succeeded() && !Tool.isEmpty(handleGetGateKey.result())){
//				String gateName = handleGetGateKey.result();
//				if(gateName != null && !gateName.isEmpty()) {
//					String address = Constant.getEventBusName(MainVerticle.getLocalName(),Constant.EVENT_BUS_GATE_RECEIVE)+"_"+gateName;
//					EventBus eventBus = MainVerticle.instance.vertxInstance.eventBus();
//					obj.put("userid", userId);
//					eventBus.send(address, obj);
//				}
//			}
//		});
//	}

//	/**
//	 * 检查是否实名认证
//	 * @return 0表示可以继续登陆 非0表示错误码
//	 */
//	public static Future<ErrorWord> checkRealName(WebClient webClient, String accountid, int accountType, int platform){
//		Promise<ErrorWord> promise = Promise.promise();
//		//非国内渠道无需实名判断
//		if (!Platform.isChinaPlatform(platform)){
//			promise.complete(ErrorWord.SUCCESS);
//			return promise.future();
//		}
//		//判断是否实名
//		String key = RedisKey.getAccountRealNameKey(accountType, accountid);
//		RedisTools.get(UtilityManager.redisClient, key, h->{
//			if (h.succeeded()){
//				if (Tool.isEmpty(h.result())){//不存在则初始化
//					//如果是魔兔SDK，则需要判断是否已经实名过
//					Future<JsonObject> futureSDK;
//					if (accountType == LoginManager.LOGIN_TYPE_MOTU_SDK){
//						futureSDK = checkMotuSDKRealName(webClient, accountid);
//					} else{
//						futureSDK = Future.succeededFuture(new JsonObject());
//					}
//					futureSDK.setHandler(handlerSDK->{
//						if (handlerSDK.succeeded()){
//							JsonObject realnameObj = handlerSDK.result();
//							String cardid = realnameObj.containsKey("cardid") ? realnameObj.getString("cardid") : "";
//							String name = realnameObj.containsKey("name") ? realnameObj.getString("name") : "";
//							String sql = "insert into account_realname(type,accountid,cardid,name,addtime) values(?,?,?,?,?);";
//							JsonArray params = new JsonArray();
//							params.add(accountType);
//							params.add(accountid);
//							params.add(cardid);
//							params.add(name);
//							params.add(Tool.getCurTime());
//							MysqlTool.updateToDb(UtilityManager.jdbcClientServer, sql, params, h1 -> {
//								if (h1.succeeded()){
//									String realname = Tool.isEmpty(cardid) ? "0" : "1";
//									RedisTools.set(UtilityManager.redisClient, key, realname, h2->{
//										if (h2.succeeded()){
//											promise.complete(ErrorWord.SUCCESS);//刚创建实名账号，可以继续登陆
//										}else{
//											promise.fail(h2.cause());
//										}
//									});
//								} else{
//									promise.fail(h1.cause());
//								}
//							});
//						} else{
//							promise.fail(handlerSDK.cause());
//						}
//					});
//				} else{//存在要判断是否实名或在线超时
//					if (h.result().equals("1")){
//						promise.complete(ErrorWord.SUCCESS);//已经实名，可以继续登陆
//					} else{//未实名要判断在线时长
//						Promise<Boolean> promiseCheckOnline = Promise.promise();//是否要判断在线时长
//						if (accountType == LoginManager.LOGIN_TYPE_MOTU_SDK){//如果是魔兔SDK，需要判断SDK是否实名
//							checkMotuSDKRealName(webClient, accountid).setHandler(handleSDK->{
//								if (handleSDK.succeeded()){
//									JsonObject result = handleSDK.result();
//									String cardid = result.getString("cardid");//身份证号
//									String name = result.getString("name");//姓名
//									if (!Tool.isEmpty(cardid)){//SDK已实名
//										String sql = "update account_realname set cardid = ?, name = ? where type = ? and accountid = ?;";
//										JsonArray params = new JsonArray();
//										params.add(cardid);
//										params.add(name);
//										params.add(accountType);
//										params.add(accountid);
//										MysqlTool.updateToDb(UtilityManager.jdbcClientServer, sql, params, h1 -> {
//											if (h1.succeeded()){
//												RedisTools.set(UtilityManager.redisClient, key, "1", h2->{
//													if (h2.succeeded()){
//														promise.complete(ErrorWord.SUCCESS);//已实名，可以继续登陆
//													}else{
//														promise.fail(h2.cause());
//													}
//												});
//											} else{
//												promise.fail(h1.cause());
//											}
//										});
//									} else{//未实名判断在线时长
//										promiseCheckOnline.complete(true);
//									}
//								} else{
//									promise.fail(handleSDK.cause());
//								}
//							});
//						} else{//未实名判断在线时长
//							promiseCheckOnline.complete(true);
//						}
//						//未实名判断在线时长
//						promiseCheckOnline.future().setHandler(handlerCheckOnline->{
//							if (handlerCheckOnline.succeeded()){
//								if (handlerCheckOnline.result()){
//									String key1 = RedisKey.getAccountOnlineTimeKey(accountType, accountid);
//									RedisTools.get(UtilityManager.redisClient, key1, h3->{
//										if (h3.succeeded()){
//											int onlinetime = Tool.isEmpty(h3.result()) ? 0 : Integer.parseInt(h3.result());
//											if (onlinetime >= ServerParam.UNREALNAME_ONLINE_MAX_TIME){
//												promise.complete(ErrorWord.ALREADY_MAX);//未实名在线超过1个小时则不能登陆
//											}else {
//												promise.complete(ErrorWord.SUCCESS);
//											}
//										}else{
//											promise.fail(h3.cause());
//										}
//									});
//								}
//							} else{
//								promise.fail(handlerCheckOnline.cause());
//							}
//						});
//					}
//				}
//			} else{
//				promise.fail(h.cause());
//			}
//		});
//		return promise.future();
//	}

    /**
     * 检查魔兔sdk是否实名
     */
    private static Future<JsonObject> checkMotuSDKRealName(WebClient webClient, String accountid) {
        Promise<JsonObject> promise = Promise.promise();
        JsonObject params = new JsonObject();
        params.put("acc", accountid);
        String requestUrl = BaseServerParam.MOTU_SDK_URL + "/checkrealname";
        logger.info("###checkMotuSDKRealName requestUrl = " + requestUrl + " params = " + params);
        webClient.postAbs(requestUrl).timeout(HTTP_REQUEST_TIMEOUT).sendJsonObject(params, h -> {
            if (h.succeeded()) {
                HttpResponse<Buffer> response = h.result();
                JsonObject resObj = response.bodyAsJsonObject();
                int resultCode = resObj.getInteger("code");
                logger.info("###checkMotuSDKRealName success result = " + resObj.toString());
                if (resultCode == 0) {
                    promise.complete(resObj);
                } else {
                    logger.error("checkMotuSDKRealName error resultCode = " + resultCode + " params = " + params.toString() + " !!!");
                    promise.fail(h.cause());
                }
            } else {
                logger.error(Tool.getException(h.cause()));
                promise.fail(h.cause());
            }
        });
        return promise.future();
    }

    /**
     * 记录魔兔sdk实名信息
     */
    public static Future<Integer> addMotuSDKRealName(WebClient webClient, String accountid, String cardid, String name) {
        Promise<Integer> promise = Promise.promise();
        JsonObject params = new JsonObject();
        params.put("acc", accountid);
        params.put("cardid", cardid);
        params.put("name", name);
        String requestUrl = BaseServerParam.MOTU_SDK_URL + "/addrealname";
        logger.info("###addMotuSDKRealName requestUrl = " + requestUrl + " params = " + params);
        webClient.postAbs(requestUrl).timeout(HTTP_REQUEST_TIMEOUT).sendJsonObject(params, h -> {
            if (h.succeeded()) {
                HttpResponse<Buffer> response = h.result();
                JsonObject resObj = response.bodyAsJsonObject();
                int resultCode = resObj.getInteger("code");
                logger.info("###addMotuSDKRealName success result = " + resObj.toString());
                promise.complete(resultCode);
            } else {
                logger.error(Tool.getException(h.cause()));
                promise.fail(h.cause());
            }
        });
        return promise.future();
    }

    /**
     * 验证实名信息
     */
    public static void verifyRealName(WebClient webClient, String cardid, String name, Handler<AsyncResult<JsonObject>> handler) {
        String url = "http://msg.m2time.net:8080/VerifyIdcardv2?gameId=motu_firehero&cardNo=" + cardid + "&realName=" + URLEncoder.encode(name, StandardCharsets.UTF_8);
        webClient.getAbs(url).timeout(30000l).send(res -> {
            if (res.succeeded()) {
                HttpResponse<Buffer> response = res.result();
                JsonObject resObj = response.bodyAsJsonObject();
                logger.info("$$$ checkRealName url:" + url + " resObj:" + resObj.toString());
                handler.handle(Future.succeededFuture(resObj));
            } else {
                handler.handle(Future.failedFuture(res.cause()));
            }
        });
    }

    //	public static void test(String args[]){
    //	    try {
    //			String playerId = "xxxx";
    //			String publicKeyUrl = "https://static.gc.apple.com/public-key/gc-prod-3.cer";
    //			String bundleId = "com.xxx.xxx.game";
    //			long timestamp = 1231231232L;
    //			String salt = "d0xRFw==";
    //			String sign = "augUgRE/INZLLARzyFe3/HoB9fA5IrxdmFUsq";
    //			byte[] data = concatContent(playerId , bundleId, timestamp, salt);
    //			byte[] signBytes = Base64.decodeBase64(sign);
    //			URL url = new URL(publicKeyUrl);
    //			HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
    //			InputStream publicKeyInputStream  = httpCon.getInputStream();
    //
    ////	    InputStream publicKeyInputStream = HttpHelper.get(publicKeyUrl);
    //			boolean result = verifySign(publicKeyInputStream , signBytes, data);
    //			System.out.println(result);
    //		} catch (MalformedURLException e) {
    //			e.printStackTrace();
    //		} catch (IOException e) {
    //			e.printStackTrace();
    //		}
    //	}
}
